package com.mega.ycy.mixin;

import com.google.common.collect.ListMultimap;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.FMLModContainer;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLEvent;
import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;

import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

@Mixin(value = FMLModContainer.class, remap = false)
public abstract class FMLModContainerMixin {
    @Shadow(remap = false) private ListMultimap<Class<? extends FMLEvent>, Method> eventMethods;

    @Shadow(remap = false) public abstract String getModId();

    @Nullable
    @Overwrite(remap = false)
    private Method gatherAnnotations(Class<?> clazz){
        Method factoryMethod = null;
        for (Method m : clazz.getDeclaredMethods())
        {
            for (Annotation a : m.getAnnotations())
            {
                if (a.annotationType().equals(Mod.EventHandler.class) || m.getName().endsWith("_"))
                {
                    System.out.println(Arrays.asList(m.getParameterTypes()).get(0));

                    System.out.println(clazz.getName() + " " + m.getName() + Arrays.toString(m.getParameters()));
                    if (m.getParameterTypes().length == 1 && FMLEvent.class.isAssignableFrom(m.getParameterTypes()[0]))
                    {
                        m.setAccessible(true);
                        @SuppressWarnings("unchecked")
                        Class<? extends FMLEvent> parameterType = (Class<? extends FMLEvent>) m.getParameterTypes()[0];
                        eventMethods.put(parameterType, m);
                    }
                    else
                    {
                        FMLLog.log.error("The mod {} appears to have an invalid event annotation {}. This annotation can only apply to methods with recognized event arguments - it will not be called", getModId(), a.annotationType().getSimpleName());
                    }
                }
                else if (a.annotationType().equals(Mod.InstanceFactory.class))
                {
                    if (Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0 && factoryMethod == null)
                    {
                        m.setAccessible(true);
                        factoryMethod = m;
                    }
                    else if (!(Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0))
                    {
                        FMLLog.log.error("The InstanceFactory annotation can only apply to a static method, taking zero arguments - it will be ignored on {}({}) for mod {}", m.getName(), Arrays.asList(m.getParameterTypes()), getModId());
                    }
                    else if (factoryMethod != null)
                    {
                        FMLLog.log.error("The InstanceFactory annotation can only be used once, the application to {}({}) will be ignored for mod {}", m.getName(), Arrays.asList(m.getParameterTypes()), getModId());
                    }
                }
            }
        }
        return factoryMethod;
    }
}
